﻿// owner 蒋家伟

#pragma once
#include "DBSchemaObject.h"
#include "DataSerializeDefine.h"
#include "ObjectReflectDeclare.h"
#include "ElementId.h"
#include "IExternalData.h"

namespace jsdk
{
    SERIALIZE_ENUM(TestAEnum)
    {
        Undefine = 0,
        Ok = 1
    };

    class ITestA
    {
        DEFINE_DRIVER_BASE(ITestA)
    public:
        virtual ~ITestA() {}
        virtual bool operator==(const ITestA& testA) const = 0;
        virtual const std::wstring& getTestString() const = 0;
        virtual int getTestInt() const = 0;
        virtual TestAEnum getEnumTest() const = 0;
        virtual void setEnum(TestAEnum enumvalue) = 0;
    };


    class TestA : public DBSchemaObject, public ITestA
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED2(jsdk, TestA, L"{E3253F7A-9B2D-4BD4-8467-2F0D109E6F74}", DBSchemaObject, ITestA)
            DATA(std::wstring, StrTest);
            DATA(int32_t, IntTest);
            DATA(TestAEnum, EnumTest);
    public:
        TestA(const std::wstring& strTest, int intTest) : m_StrTest(strTest), m_IntTest(intTest){}
        bool operator==(const ITestA& testA) const override;
        virtual const std::wstring& getTestString()  const override { return getStrTest__(); };
        virtual int getTestInt() const override { return getIntTest__(); };
        virtual const IElement* getTopLevelElement() const override { return nullptr; };
        virtual TestAEnum getEnumTest() const override { return getEnumTest__(); }
        virtual void setEnum(TestAEnum enumvalue) override { setEnumTest__(enumvalue); };
    };

    class TestA2 : public DBSchemaObject, public ITestA
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED2(jsdk, TestA2, L"{1FA2C2FE-EF57-4F35-8E73-C6A1111DD69D}", DBSchemaObject, ITestA)
            DATA(std::wstring, StrTest);
            DATA(int32_t, IntTest);
            DATA(int16_t, Int16Test);
            DATA(TestAEnum, EnumTest);
    public:
        TestA2(const std::wstring& strTest, int intTest, int16_t int16) : m_StrTest(strTest), m_IntTest(intTest), m_Int16Test(int16) {}
        bool operator==(const ITestA& testA) const override; 
        virtual const std::wstring& getTestString()  const override { return getStrTest__(); };
        virtual int getTestInt() const override { return getIntTest__(); };
        virtual const IElement* getTopLevelElement() const override { return nullptr; };
        virtual void setEnum(TestAEnum enumvalue) override { setEnumTest__(enumvalue); };
        virtual TestAEnum getEnumTest() const override { return getEnumTest__(); }
    };

    class TestB : public DBSchemaObject
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED1(jsdk, TestB, L"{21C60B66-DF97-4DD1-A70F-56FD1804113B}", DBSchemaObject)
            DATA(std::wstring, StrTest);
            DATA(int32_t, IntTest);
            DATA(OwnerPtr<ITestA>, opITestATest);
            DATA(OwnerPtr<ITestA>, opITestA2Test);
            DATA(OwnerPtr<TestA>, opTestATest);
            DATA(ElementId, elementId);
            DATA(float, floatTest);

    public:
        TestB(const std::wstring& strTest, int intTest, jsdk::ElementId id) : m_StrTest(strTest), m_IntTest(intTest), m_elementId(id) {}
        virtual const std::wstring& getTestString() const { return getStrTest__(); };
        virtual const int getTestInt() const { return getIntTest__(); };
        virtual const IElement* getTopLevelElement() const override { return nullptr; };
        const OwnerPtr<ITestA>& getopTestA2Test() const { return getopITestA2Test__(); }
        void setopITestA2Test(OwnerPtr<ITestA> opTestA2Test) { setopITestA2Test__(jsdk::transformOwnerShip(opTestA2Test)); }
        const OwnerPtr<ITestA>& getopITestATest() const { return getopITestATest__(); }
        void setopITestATest(OwnerPtr<ITestA> opITestATest) { setopITestATest__(jsdk::transformOwnerShip(opITestATest)); }
        const OwnerPtr<TestA>& getopTestATest() const { return getopTestATest__(); }
        void setopTestATest(OwnerPtr<TestA> opTestA) { setopTestATest__(jsdk::transformOwnerShip(opTestA)); }
        void setFloatTest(float a) { setfloatTest__(a); }
        float getFloatTest() const { return getfloatTest__(); }
        bool operator==(const TestB& testB) const;
    };

    class TestVectorBaseType : public DBSchemaObject
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED1(jsdk, TestVectorBaseType, L"{38361AFA-FA6D-4C5D-A66C-D5BE8D4EF8C7}", DBSchemaObject)
            DATA_ARRAY(std::string, DbVectorStr)
    public:
        std::vector<std::string>& getFWDbVectorStr() { return getDbVectorStrFW__(); };
        const std::vector<std::string>& getDbVectorStr() const { return getDbVectorStr__(); };
        bool operator==(const TestVectorBaseType& vector);
    };

    class TestVectorOwnerPtr : public DBSchemaObject
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED1(jsdk, TestVectorOwnerPtr, L"{B0C2B0C2-A112-4C6A-AF1B-EFAAC92ADA66}", DBSchemaObject)
            DATA_ARRAY(OwnerPtr<TestA>, DbVectorTestA)
            DATA_ARRAY(OwnerPtr<ITestA>, DbVectorITestA)
            DATA_ARRAY(OwnerPtr<TestB>, DbVectorTestB)

    public:
        std::vector<OwnerPtr<TestA>>& getFWDbVectorTestA() { return getDbVectorTestAFW__(); };
        const std::vector<OwnerPtr<TestA>>& getDbVectorTestA() const { return getDbVectorTestA__(); };
        std::vector<OwnerPtr<ITestA>>& getFWDbVectorITestA() { return getDbVectorITestAFW__(); };
        const std::vector<OwnerPtr<ITestA>>& getDbVectorITestA() const { return getDbVectorITestA__(); };
        std::vector<OwnerPtr<TestB>>& getFWDbVectorTestB() { return getDbVectorTestBFW__(); };
        const std::vector<OwnerPtr<TestB>>& getDbVectorTestB() const { return getDbVectorTestB__(); };
        bool operator==(const TestVectorOwnerPtr& vector) const;
    };

    struct OwnerPtrTestACP
    {
        bool operator()(const OwnerPtr<TestA>& opLeft, const OwnerPtr<TestA>& opRight) const
        {
            if (opLeft && opRight)
            {
                return opLeft->getTestInt() < opRight->getTestInt();
            }
            return false;
        }
    };

    class TestSetBaseType : public DBSchemaObject
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED1(jsdk, TestSetBaseType, L"{9D895935-E29B-4EB3-BB24-8ABF96018690}", DBSchemaObject)
            DATA_SET(std::wstring, DbSetStr)
            DATA_SET_WITH_COMPARATOR(OwnerPtr<TestA>, OwnerPtrTestACP, DbSetTestA)
    public:
        std::set<OwnerPtr<TestA>, OwnerPtrTestACP>& getDbSetTestAFw() { return getDbSetTestAFW__(); }
        std::set<std::wstring>& getDbSetStrFw() { return getDbSetStrFW__(); }
        bool operator==(const TestSetBaseType& set) const;
    };

    class TestMap : public DBSchemaObject
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED1(jsdk, TestMap, L"{8BAB1100-35FC-4C06-93CE-E6085D6850E2}", DBSchemaObject)
            DATA_MAP(std::wstring, OwnerPtr<TestA>, StringToTestAMap)
            DATA_MAP(int32_t, std::string, IntToStringMap)
            DATA_UMAP(std::wstring, OwnerPtr<TestA>, StringToTestUMap)
            DATA_UMAP(int32_t, std::string, IntToStringUMap)

    public:
        std::map<std::wstring, OwnerPtr<TestA>>& getStringToTestAMapFw() { return getStringToTestAMapFW__(); }
        std::map<int32_t, std::string>& getIntToStringMapFw() { return getIntToStringMapFW__(); }

        std::unordered_map<std::wstring, OwnerPtr<TestA>>& getStringToTestAUMapFw() { return getStringToTestUMapFW__(); }
        std::unordered_map<int32_t, std::string>& getIntToStringUMapFw() { return getIntToStringUMapFW__(); }
        bool operator==(const TestMap& map) const;
    };

    struct PersonInput
    {
        ElementId FatherId = ElementId::s_InvalidId;
        ElementId MotherId = ElementId::s_InvalidId;
        uint16_t Height{};
        float Weight{};
    };

    class Person : public DBSchemaObject, public IExternalData
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED2(jsdk, Person, L"{F7469D00-F99E-491C-AD97-BD1759A58B7E}", DBSchemaObject, IExternalData)
            DATA_CUSTOM(IElement*, pOwnerElement)
            DATA(uint16_t, height)
            DATA(float, weight)
            DATA_SET(jsdk::ElementId, friends)
            DATA(ElementId, father)
            DATA(ElementId, mother)

    public:
        static IElement* create(const PersonInput& input);
        static Person* getFw(IDocument* pDoc, const ElementId& id);
        static const Person* get(const IDocument* pDoc, const ElementId& id);

    public:
        uint16_t getHeight() const { return getheight__(); }
        float getWeight() const { return getweight__(); }
        void setHeight(uint16_t height_cm) { setheight__(height_cm); }
        void setWeight(float weight_kg) { setweight__(weight_kg); }
        ElementId getMotherId() const { return getmother__(); }
        ElementId getFatherId() const { return getfather__(); }

        void addFriendId(const ElementId& friendId);
        void deleteFriendId(const ElementId& friendId);

    private:
        // 继承IExternalData
        virtual const IElement* getOwnerElement() const override { return getpOwnerElement__(); };
        virtual IElement* getOwnerElement() override { return getpOwnerElementFW__(); };
        virtual void setOwnerElement(IElement* pElement) override { setpOwnerElement__(pElement); };
        virtual const IElement* getTopLevelElement() const { return getOwnerElement(); };
    };

    struct GodInput
    {
        ElementId FatherId = ElementId::s_InvalidId;
        ElementId MotherId = ElementId::s_InvalidId;
        uint16_t Height{};
        float Weight{};
    };

    class God : public DBSchemaObject, public IExternalData
    {
        OBJECT_SERIALIZE_DECLARE_DERIVED2(jsdk, God, L"{69CC3078-477A-4B75-B501-6A8AF8591905}", DBSchemaObject, IExternalData)
            DATA_CUSTOM(IElement*, pOwnerElement)
            DATA(uint16_t, height)
            DATA(float, weight)

    public:
        static IElement* create(const GodInput& input);
        static God* getFw(IDocument* pDoc, const ElementId& id);
        static const God* get(const IDocument* pDoc, const ElementId& id);

    public:
        uint16_t getHeight() const { return getheight__(); }
        float getWeight() const { return getweight__(); }
        void setHeight(uint16_t height_cm) { setheight__(height_cm); }
        void setWeight(float weight_kg) { setweight__(weight_kg); }

    private:
        // 继承IExternalData
        virtual const IElement* getOwnerElement() const override { return getpOwnerElement__(); };
        virtual IElement* getOwnerElement() override { return getpOwnerElementFW__(); };
        virtual void setOwnerElement(IElement* pElement) override { setpOwnerElement__(pElement); };
        virtual const IElement* getTopLevelElement() const { return getOwnerElement(); };
    };
}